﻿using LightCAD.Core.Elements;
using LightCAD.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LightCAD.Core.Element3d
{
    public class ExtrudeAttribute : CptAttribute
    {
        public ExtrudeAttribute(string category, string subCategorys) : base(category, subCategorys)
        {
        }
        public override LcComponentDefinition GetBuiltinCpt(string subCategory)
        {
            return null;
        }
    }
    [ExtrudeAttribute("拉伸体", "拉伸体")]
    public class LcExtrudeDef : LcComponentDefinition
    {
        static LcExtrudeDef()
        {
            CptTypeParamsDef<LcExtrudeDef>.ParamsDef = new ParameterSetDefinition {
                new ParameterDefinition { DataType = LcDataType.String, Name = "MaterialId", DisplayName = "材质", },
             new ParameterDefinition { DataType = LcDataType.String, Name = "SectionId", DisplayName = "截面", }
            };
        }
        public LcExtrudeDef()
        {
            this.TypeParameters = new LcParameterSet(CptTypeParamsDef<LcExtrudeDef>.ParamsDef);
        }
        public LcExtrudeDef(string uuid, string name, string sectionId) : base(uuid, name, "拉伸体", "拉伸体", new LcParameterSet(CptTypeParamsDef<LcExtrudeDef>.ParamsDef))
        {
            this.TypeParameters.SetValue("SectionId", sectionId);
            this.Parameters = new ParameterSetDefinition
                {
                    new ParameterDefinition { Name = "Depth", DataType = LcDataType.Double } ,
                    new ParameterDefinition { Name = "TopScale", DataType = LcDataType.Double } ,
                    new ParameterDefinition { Name = "BottomScale", DataType = LcDataType.Double } ,
                    new ParameterDefinition { Name = "Normal", DataType = LcDataType.Point3d } ,

                };
            this.Curve2dProvider = new Curve2dProvider("拉伸体")
            {
                GetCurve2dsFunc = (p) =>
                {
                    var depth = p.GetValue<double>("Depth");
                    var topScale = p.GetValue<double>("TopScale");
                    var bottomScale = p.GetValue<double>("BottomScale");
                    var normal = p.GetValue<Vector3>("Normal");
                    var sectionId = this.TypeParameters.GetValue<string>("SectionId");
                    var offset = normal.Clone().Normalize().MulScalar(depth).ToVector2();
                    if (SectionManager.Sections.TryGetValue(sectionId, out var section))
                    {
                        var curve2ds = section.Segments.Clone().SelectMany(n =>
                        {
                            List<Curve2d> curs = new List<Curve2d>();
                            if (n is Arc2d)
                            {
                                var arcB = n.Clone() as Arc2d;
                                arcB.Center.MultiplyScalar(bottomScale);
                                arcB.Radius *= bottomScale;
                                curs.Add(arcB);
                                if (normal!=new Vector3(0,0,1)||bottomScale!=topScale)
                                {
                                    var arcT = n.Clone() as Arc2d;
                                    arcT.Center.MultiplyScalar(topScale);
                                    arcT.Radius *= topScale;
                                    arcT.Translate(offset);
                                    curs.Add(arcT);
                                    //var sweepAngle = Utils.AngelNormalize(arcT.EndAngle - arcT.StartAngle);
                                    //var count = (int)Math.Ceiling((arcT.IsClockwise ? Utils.TwoPI - sweepAngle : sweepAngle) / Utils.TwoPI * 32);
                                    //var arcTps = arcT.GetPoints(count);
                                    //var arcBps = arcB.GetPoints(count);
                                    //for (var k = 0; k < count - 1; k++)
                                    //{
                                    //    var roundLine = new Line2d(arcTps[k].Clone(), arcBps[k].Clone());
                                    //    curs.Add(roundLine);
                                    //}
                                }
                                return curs;
                            }
                            else
                            {
                                var lineT = n.Clone() as Line2d;
                                lineT.Start.MultiplyScalar(topScale);
                                lineT.End.MultiplyScalar(topScale);
                                lineT.Translate(offset);
                                curs.Add(lineT);
                                if (normal != new Vector3(0, 0, 1) || bottomScale != topScale)
                                {
                                    var lineB = n.Clone() as Line2d;
                                    lineB.Start.MultiplyScalar(bottomScale);
                                    lineB.End.MultiplyScalar(bottomScale);
                                    curs.Add(lineB);
                                    var connectLine = new Line2d(lineT.Start.Clone(),lineB.Start.Clone());
                                    curs.Add(connectLine);
                                }
                                return curs;
                            }
                        }).ToList();
                        var inCurve2ds = section.InnerSegments.Clone().SelectMany(m =>
                        {
                             return m.SelectMany(n =>
                            {
                                List<Curve2d> curs = new List<Curve2d>();
                                if (n is Arc2d)
                                {
                                    var arcB = n.Clone() as Arc2d;
                                    arcB.Center.MultiplyScalar(bottomScale);
                                    arcB.Radius *= bottomScale;
                                    curs.Add(arcB);
                                    if (normal != new Vector3(0, 0, 1) || bottomScale != topScale)
                                    {
                                        var arcT = n.Clone() as Arc2d;
                                        arcT.Center.MultiplyScalar(topScale);
                                        arcT.Radius *= topScale;
                                        arcT.Translate(offset);
                                        curs.Add(arcT);
                                        var connectLine = new Line2d(arcT.GetPoints(1).First(), arcB.GetPoints(1).First());
                                        curs.Add(connectLine);
                                        //var sweepAngle = Utils.AngelNormalize(arcT.EndAngle - arcT.StartAngle);
                                        //var count = (int)Math.Ceiling((arcT.IsClockwise ? Utils.TwoPI - sweepAngle : sweepAngle) / Utils.TwoPI * 32);
                                        //var arcTps = arcT.GetPoints(count);
                                        //var arcBps = arcB.GetPoints(count);
                                        //for (var k = 0; k < count - 1; k++)
                                        //{
                                        //    var roundLine = new Line2d(arcTps[k].Clone(), arcBps[k].Clone());
                                        //    curs.Add(roundLine);
                                        //}
                                    }
                                }
                                else
                                {
                                    var lineB = n.Clone() as Line2d;
                                    lineB.Start.MultiplyScalar(bottomScale);
                                    lineB.End.MultiplyScalar(bottomScale);
                                    curs.Add(lineB);
                                    if (normal != new Vector3(0, 0, 1) || bottomScale != topScale)
                                    {
                                        var lineT = n.Clone() as Line2d;
                                        lineT.Start.MultiplyScalar(topScale);
                                        lineT.End.MultiplyScalar(topScale);
                                        lineT.Translate(offset);
                                        curs.Add(lineT);
                                        var connectLine = new Line2d(lineT.Start.Clone(), lineB.Start.Clone());
                                        curs.Add(connectLine);
                                    }
                                }
                                return curs;
                            }); 
                        });
                        curve2ds.AddRange(inCurve2ds);
                        return new Curve2dGroupCollection() { new Curve2dGroup()
                        {
                            Curve2ds = curve2ds.ToListEx()

                        } };
                    }
                    return new Curve2dGroupCollection() { new Curve2dGroup()
                        {
                            Curve2ds=new ListEx<Curve2d>
                            {
                            }
                        } };
                }
            };
            this.Solid3dProvider = new Solid3dProvider("拉伸体")
            {
                GetSolid3dsFunc = (p) =>
                {
                    var depth = p.GetValue<double>("Depth");
                    var topScale = p.GetValue<double>("TopScale");
                    var bottomScale = p.GetValue<double>("BottomScale");
                    var normal = p.GetValue<Vector3>("Normal");
                    var sectionId = this.TypeParameters.GetValue<string>("SectionId");
                    PlanarSurface3d profile;
                    if (SectionManager.Sections.TryGetValue(sectionId, out var section))
                    {
                        var curve3ds = section.Segments.Select(n =>
                        {
                            Curve3d curve;
                            if (n is Line2d line)
                            {
                                curve = new Line3d(line.Start.ToVector3(), line.End.ToVector3());
                            }
                            else
                            {
                                var arc = n as Arc2d;
                                curve = new Arc3d(arc.Center.ToVector3(), arc.Radius, arc.StartAngle, arc.EndAngle, arc.IsClockwise);
                            }
                            return curve;
                        }).ToList();
                        var inCurve3ds = section.InnerSegments.Select(m => m.Select(n =>
                        {
                            Curve3d curve;
                            if (n is Line2d line)
                            {
                                curve = new Line3d(line.Start.ToVector3(), line.End.ToVector3());
                            }
                            else
                            {
                                var arc = n as Arc2d;
                                curve = new Arc3d(arc.Center.ToVector3(), arc.Radius, arc.StartAngle, arc.EndAngle, arc.IsClockwise);
                            }
                            return curve;
                        }).ToList());
                        profile = new PlanarSurface3d(new Plane(new Vector3(0, 0, 1)), curve3ds);
                        profile.InnerLoops.AddRange(inCurve3ds);
                        return new Solid3dCollection { new Extrude3d(profile, normal, depth, topScale, bottomScale) };
                    }
                    else
                    {
                        return null;
                    }
                }
            };
        }
    }

    public class LcExtrudeInstance : LcComponentInstance
    {
        public LcExtrudeInstance(LcExtrudeDef lcExtrude) : base(lcExtrude)
        {
            this.Type = BuiltinElementType.Extrude;
            var sectionId = lcExtrude.TypeParameters.GetValue<string>("SectionId");
            /// 有隐患，可能导致GC无法回收实例
            SectionManager.Sections[sectionId].PropertyChangedAfter += (sender, e) =>
            {
                this.UpdateExtrudeSection();
            };
        }
        public LcExtrudeInstance(double depth, double topScale, double bottomScale, Vector3 normal, LcExtrudeDef lcExtrude) : this(lcExtrude)
        {
            this.Parameters.SetValue("Depth", depth);
            this.Parameters.SetValue("TopScale", topScale);
            this.Parameters.SetValue("BottomScale", bottomScale);
            this.Parameters.SetValue("Normal", normal);
        }
        public void UpdateExtrudeSection()
        {
            this.OnPropertyChangedBefore("Section",null,null);
            this.ResetCache();
            this.OnPropertyChangedAfter("Section", null, null);
        }
        public override LcExtrudeInstance Clone()
        {
            LcExtrudeInstance lcExtrude = new LcExtrudeInstance((LcExtrudeDef)this.Definition);
            lcExtrude.Copy(this);
            return lcExtrude;
        }
        public override void Copy(LcElement src)
        {
            base.Copy(src);
        }
    }
    ///// <summary>
    ///// 长方体
    ///// </summary>
    //public class LcExtrude : LcSolid3d
    //{
    //    public Extrude3d Extrude => this.Solid as Extrude3d;
    //    public LcSection Section { get; set; }
    //    public LcExtrude()
    //    {
    //        this.Solid = new Extrude3d();

    //    }
    //    public LcExtrude(PlanarSurface3d profile, double depth, double topRatio,double bottomRatio,Vector3 normal,params LcMaterial[] mats) : this()
    //    {
    //        this.Extrude.Normal= normal;
    //        this.Extrude.SetSize(profile, depth, topRatio, bottomRatio);
    //        this.Materials = mats;
    //    }

    //}
}
